package com.only4play.portal.cp.message;

import com.only4play.portal.common.error.PortalErrorExceptionHandler;
import com.only4play.portal.common.error.PortalErrorException;
import com.only4play.portal.common.session.PortalSessionManager;
import com.only4play.portal.cp.api.CpService;
import com.only4play.portal.cp.bean.message.AbstractCpMessage;
import com.only4play.portal.cp.bean.message.AbstractCpOutMessage;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author liyuncong
 * @version 1.0
 * @file
 * @brief
 * @details
 * @date 2024-06-07
 *
 * Edit History
 * ----------------------------------------------------------------------------
 * DATE                     NAME               DESCRIPTION
 * 2024-06-07               liyuncong          Created
 */

@Getter
@Setter
public abstract class CpMessageRouterRule<CpOutMessage extends AbstractCpOutMessage, CpMessage extends AbstractCpMessage> {
    private final CpMessageRouter<CpOutMessage, CpMessage> routerBuilder;

    protected boolean async = true;

    protected String fromUser;

    protected String msgType;

    protected String event;

    protected String eventKey;

    protected String eventKeyRegex;

    protected String content;

    protected String rContent;

    protected CpMessageMatcher<CpOutMessage, CpMessage> matcher;

    protected boolean reEnter = false;

    protected Integer agentId;

    protected List<CpMessageHandler<CpOutMessage, CpMessage>> handlers = new ArrayList<>();

    protected List<CpMessageInterceptor> interceptors = new ArrayList<>();


    protected CpMessageRouterRule(CpMessageRouter<CpOutMessage, CpMessage> routerBuilder) {
        this.routerBuilder = routerBuilder;
    }

    public CpMessageRouterRule<CpOutMessage, CpMessage> async(boolean async) {
        this.async = async;
        return this;
    }

    public CpMessageRouterRule<CpOutMessage, CpMessage> msgType(String msgType) {
        this.msgType = msgType;
        return this;
    }

    public CpMessageRouterRule<CpOutMessage, CpMessage> event(String event) {
        this.event = event;
        return this;
    }

    public CpMessageRouterRule<CpOutMessage, CpMessage> handler(CpMessageHandler<CpOutMessage, CpMessage> handler) {
        return handler(handler, (CpMessageHandler<CpOutMessage, CpMessage>[]) null);
    }

    @SafeVarargs
    protected final CpMessageRouterRule<CpOutMessage, CpMessage> handler(
        CpMessageHandler<CpOutMessage, CpMessage> handler,
        CpMessageHandler<CpOutMessage, CpMessage>... otherHandlers
    ) {
        this.handlers.add(handler);
        if (otherHandlers != null && otherHandlers.length > 0) {
            Collections.addAll(this.handlers, otherHandlers);
        }
        return this;
    }

    /**
     * 规则结束，但是消息还会进入其他规则
     *
     * @return
     */
    public CpMessageRouter<CpOutMessage, CpMessage> next() {
        this.reEnter = true;
        return end();
    }

    /**
     * 规则结束，代表如果一个消息匹配该规则，那么它将不再会进入其他规则
     *
     * @return
     */
    public CpMessageRouter<CpOutMessage, CpMessage> end() {
        this.routerBuilder.getRules().add(this);
        return this.routerBuilder;
    }

    protected CpOutMessage service(
        CpMessage cpMessage,
        Map<String, Object> context,
        CpService portalCpService,
        PortalSessionManager sessionManager,
        PortalErrorExceptionHandler exceptionHandler
    ) {
        if (context == null) {
            context = new HashMap<>();
        }

        try {
            // 如果拦截器不工作
            for (CpMessageInterceptor interceptor : this.interceptors) {
                if (!interceptor.intercept(cpMessage, context, portalCpService, sessionManager)) {
                    return null;
                }
            }

            // 交给handler处理
            CpOutMessage outMessage = null;
            for (CpMessageHandler<CpOutMessage, CpMessage> handler : this.handlers) {
                // 返回最后handler的结果
                outMessage = handler.handle(cpMessage, context, portalCpService, sessionManager);
            }
            return outMessage;

        } catch (PortalErrorException exception) {
            exceptionHandler.handle(exception);
        }

        return null;
    }

    protected abstract boolean attemptMatch(CpMessage cpMessage);

}
